#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include <pthread.h>

#include "yield.h"
#include "randomize.h"
#include "env.h"

const unsigned int CYCLE_NUM = 500;
const char def_file[] = "Spanish.txt";
const int HILO_READ = 10;
const int HILO_WRITE = 10;

// Prototipos internos
static void create_shared(void);
static void destroy_shared(void);
void env_read(void);
void env_write(void);
/* variables globales, datos compartidos */

/* el diccionario lineal */
char** dict_key = NULL;
char** dict_value = NULL;
unsigned int dict_size = 0;


char *a_dict_value=NULL;


/* el diccionario log(N) sobre el que actuan lectores/escritores */
env an_env = NULL;


int
main(void)
{
	
	pthread_t hilo[HILO_READ];
	pthread_t hilo2[HILO_WRITE];
	int i=0;

	#ifdef __DEBUG
	printf("Debugging activado\n");

	#endif

	create_shared();
	
	for (i=0;i<HILO_READ;i++)
	{
		pthread_create(&hilo[i], NULL,(void *) &env_read,  NULL);

	}

	for (i=0;i<HILO_WRITE;i++)
	{
		pthread_create(&hilo2[i], NULL,(void *) &env_write,  NULL);

	}

	for (i=0;i<HILO_WRITE;i++)
	{
		pthread_join(hilo2[i], NULL);

	}



	for (i=0;i<HILO_READ;i++)
	{
		pthread_join(hilo[i], NULL);

	}

	
	destroy_shared();
	printf ("FIN\n");
	return 0;
}

void env_read(void)
{
	int idx=0;
	int cycle;
	yield0();
	
	
	for(cycle=0; cycle<CYCLE_NUM; cycle++) {
		
		idx = rand()%dict_size;
		
		
		a_dict_value = env_get(an_env, dict_key[idx]);
		
		printf("Lector: %s -> '%s'\n",
			dict_key[idx], a_dict_value);
		free(a_dict_value); a_dict_value = NULL;
		
		
	}
	

}

void env_write(void)
{	
	int cycle;
	int idx=0;
	
	randomize();
	
	for(cycle=0; cycle<CYCLE_NUM; cycle++) {
		
		idx = rand()%dict_size;
			
		printf("Escritor: %s <- '%s'\n",
			dict_key[idx], dict_value[idx]);
		env_set(an_env, dict_key[idx], dict_value[idx], true);
	
		
	}
	
}


/* inicializa las estructuras compartidas */
static void create_shared(void) {
	unsigned int idx = 0, rnd_idx = 0;
	unsigned int defs = 0;
	FILE *fp = NULL;
	const unsigned int MAX_KEY = 128;
	const unsigned int MAX_VALUE = 768;
	const unsigned int MAX_LINE = MAX_KEY + MAX_VALUE + 2;
	char *a_key = NULL, *a_value = NULL, *a_line = NULL;

	assert(MAX_KEY+MAX_VALUE < MAX_LINE);
	a_key = (char *)calloc(MAX_KEY, sizeof(char));
	a_value = (char *)calloc(MAX_VALUE, sizeof(char));
	a_line = (char *)calloc(MAX_LINE, sizeof(char));
	fp = fopen(def_file, "r");
	defs = 0;
	while (!feof(fp)) {
		if (fgets(a_line, MAX_LINE, fp)!=NULL)
			if (a_line[0]!='#')
				defs++;
	}
	dict_size = defs;
	assert(0<dict_size);

	dict_key = calloc(dict_size, sizeof(char *));
	dict_value = calloc(dict_size, sizeof(char *));
	rewind(fp);
	idx = 0;
	while(idx<dict_size && !feof(fp)){
		/* aqui hay un posible problema si la linea no entra */
		fgets(a_line, MAX_LINE, fp);
		if (a_line[0]!='#') {
			sscanf(a_line,"%s%*[ \t]%[^\n]", a_key, a_value);
			dict_key[idx] = strdup(a_key);
			dict_value[idx] = strdup(a_value);
			idx++;
		}
	}
	fclose(fp);
	free(a_key); a_key = NULL;
	free(a_value); a_value = NULL;
	free(a_line); a_line = NULL;
	assert(idx==dict_size);

	/* agregado aleatorio al Env */
	an_env = env_create();
	for(idx=0; idx<dict_size; idx++) {
		rnd_idx = rand()%dict_size;
		env_set(an_env, dict_key[rnd_idx], dict_value[rnd_idx], true);
	}
	/* notar que muy probablemente an_env tenga menos de
	 * dict_size definiciones */
}

static void destroy_shared(void) {
	unsigned int i = 0;

	for(i=0; i<dict_size; i++) {
		free(dict_key[i]); 
		free(dict_value[i]); 
	}
	free(dict_key); dict_key = NULL;
	free(dict_value); dict_key = NULL;

	env_destroy(an_env); an_env = NULL;
}
